package edu.nus.mtech.sem1.ca.main.dao;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import edu.nus.mtech.sem1.ca.auth.User;
import edu.nus.mtech.sem1.ca.cust.Customer;
import edu.nus.mtech.sem1.ca.cust.complaint.Complaint;
import edu.nus.mtech.sem1.ca.data.Database;
import edu.nus.mtech.sem1.ca.data.DatabaseLoader;
import edu.nus.mtech.sem1.ca.exception.CustomerNotFoundException;
import edu.nus.mtech.sem1.ca.exception.DuplicateException;
import edu.nus.mtech.sem1.ca.exception.NotAuthenticatedException;
import edu.nus.mtech.sem1.ca.plan.Account;
import edu.nus.mtech.sem1.ca.plan.Plan;
import edu.nus.mtech.sem1.ca.txn.Transaction;
import edu.nus.mtech.sem1.ca.utils.Logger;
import edu.nus.mtech.sem1.ca.utils.TelephonyConstants;

/**
 * Entry point into the database. All database transactions should go through me
 *
 */
public class TelephonyApplicationDao {
	
	private Database database;
	
	public TelephonyApplicationDao() {
		database=DatabaseLoader.getInstance().getDatabase();
	}
	
	/**
	 * Verifies the authenticity of the logged in user
	 * @param username
	 * @param password
	 * @return
	 * @throws NotAuthenticatedException
	 */
	public User login(String username, String password) throws NotAuthenticatedException{
		Map<String, User> userMap = database.getUserMap();

		if(userMap!=null){
			if (username!=null && password!=null){
				User user = userMap.get(username);
				
				if (user!=null && password.equals(user.getPassword())){
					return user;
				}
				else{
					throw new NotAuthenticatedException();
				}
			}
			else{
				throw new NotAuthenticatedException(TelephonyConstants.ERR_USER_NAME_PASSWORD_NULL);
			}
		}
		else{
			throw new NotAuthenticatedException(TelephonyConstants.ERR_USER_DATA_NOT_AVAIL);
		}
		
	}
	
	/**
	 * Retrieves Customer object given an nric
	 * @param nric
	 * @return
	 * @throws CustomerNotFoundException
	 */
	public Customer retrieveCustomerData(String nric) throws CustomerNotFoundException{
		
		Customer customer=null;
		
		if (nric!=null){
			Map<String, Customer> customerMap = database.getCustomerMap();
			if(customerMap!=null){
				customer=customerMap.get(nric.toUpperCase());
			}
		}
		
		if (customer==null){
			System.err.println(TelephonyConstants.ERR_NO_CUSTOMER_FOUND);
			throw new CustomerNotFoundException();
		}
		
		return customer;
		
	}
	
	/**
	 * Get all customers 
	 * @return
	 * @throws CustomerNotFoundException
	 */
	public Set<Customer> retrieveAllCustomers() throws CustomerNotFoundException{
		
		Set<Customer> returnSet=new HashSet<Customer>();
		
		Map<String, Customer> customerMap = database.getCustomerMap();
		
		if (customerMap==null){
			System.err.println(TelephonyConstants.ERR_NO_CUSTOMER_FOUND);
			throw new CustomerNotFoundException();
		}
		else{
			Set<Entry<String, Customer>> entrySet = customerMap.entrySet();
			if(entrySet!=null){
				for (Entry<String, Customer> entry : entrySet) {
					
					returnSet.add(entry.getValue());
				}
			}
			
		}
		return returnSet;
		
	}
	
	/**
	 * Retrieves all complaints pertaining to a customer
	 * @param nric
	 * @return
	 */
	public Set<Complaint> retrieveComplaintsForCustomer(String nric){
		
		Set<Complaint> complaints=null;
		
		if (nric!=null){
			Map<String, Set<Complaint>> complaintsMap = database.getComplaintMap();
			if(complaintsMap!=null)
				complaints=complaintsMap.get(nric.toUpperCase());			
		}
		
		if (complaints==null){
			Logger.log(TelephonyConstants.MSG_NO_COMPLAINTS_FOUND);
		}
		
		return complaints;
		
	}
	
	/**
	 * Adds or updates the database based on whether the complaint is already lodged by the customer. 
	 * @param nric
	 * @param complaint
	 */
	public void addOrUpdateComplaintForCustomer(String nric, Complaint complaint){

		if (nric!=null && complaint!=null){
			database.addToComplaintMap(nric.toUpperCase(), complaint);
		}
		
		
	}
	
	/**
	 * Adds customer to the map to be later saved to the spreadsheet on exit
	 * @param nric
	 * @param customer
	 */
	public void registerCustomer(String nric, Customer customer){
		if(nric!=null && customer!=null){
			database.addToCustomerMap(nric.toUpperCase(), customer);
		}
	}
	
	/**
	 * De-registers customer. 
	 * @param nric
	 */
	public void deRegisterCustomer(String nric){
		if(nric!=null){
			database.removeFromCustomerMap(nric.toUpperCase());
		}
	}
	
	/**
	 * Save an account against a customer nric
	 * @param nric
	 * @param account
	 */
	public void saveAccountForCustomer(String nric, Account account) {

		Logger.log("nric "+nric);
		Logger.log("account "+account);
		database.getAccountMap().put(nric.toUpperCase(), account);
		
		Logger.log("Looping through the account information ....");
		Set<Entry<String, Account>> entrySet = database.getAccountMap().entrySet();
		for (Entry<String, Account> entry : entrySet) {
			Logger.log("Account nric: "+entry.getKey());
			Logger.log("Account value: "+entry.getValue());
		}
		Logger.log("Account saved");
	}

	
	/**
	 * Returns Transaction map. Transactions are read only. 
	 * Should ideally make a deep copy and give it to the front end. 
	 * @return
	 */
	public Map<String, Set<Transaction>> getTransactionData(){
		Map<String, Set<Transaction>> transactionMap = database.getTransactionMap();
		return transactionMap;
	}
	
	
	
	
}
